/*
 * Debts Manager. Simple android application for managing debts.
 * Copyright (C) 2010 Maxim Manuylov
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
 */

package manuylov.maxim.dm.activity;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import manuylov.maxim.common.util.GenericProcessor;
import manuylov.maxim.common.util.Pair;
import manuylov.maxim.dm.Constants;
import manuylov.maxim.dm.R;
import manuylov.maxim.dm.data.DataManager;
import manuylov.maxim.dm.data.object.Person;
import manuylov.maxim.dm.data.object.SimpleObject;
import manuylov.maxim.dm.data.object.Subject;
import manuylov.maxim.dm.data.util.DataActionResultProcessor;
import manuylov.maxim.dm.data.util.DataProcessor;
import manuylov.maxim.dm.data.util.DataUtil;
import manuylov.maxim.dm.view.ImprovedAutoCompleteTextEdit;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Settings extends BaseDMActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.settings);

        setTitle(R.string.settings);

        final ListView settingsList = (ListView) findViewById(R.id.settings_list);
        final SettingsListAdapter adapter = new SettingsListAdapter(this);

        adapter.add(android.R.layout.simple_list_item_2, getViewProcessor2(R.string.default_person, Constants.DEFAULT_PERSON,
                R.string.type_default_person, R.string.default_person_was_successfully_changed, new DataProcessor<List<String>>() {
                    public List<String> process(final DataManager dataManager) {
                        return getAllPersons(dataManager);
                    }
                }));

        adapter.add(android.R.layout.simple_list_item_1, getViewProcessor1(R.string.inactive_persons, new DataProcessor<List<Person>>() {
            public List<Person> process(final DataManager dataManager) {
                return dataManager.getInactivePersons();
            }
        }, R.string.no_inactive_persons, R.string.choose_persons_to_remove, R.string.please_choose_at_least_one_person, new ActionRunner<Person>() {
            public void performAction(final DataManager dataManager, final List<Person> objects, final boolean[] checked) {
                dataManager.removePersons(objects, checked);
            }
        }, R.string.selected_persons_were_successfully_removed));

        adapter.add(android.R.layout.simple_list_item_2, getViewProcessor2(R.string.default_subject, Constants.DEFAULT_SUBJECT,
                R.string.type_default_subject, R.string.default_subject_was_successfully_changed, new DataProcessor<List<String>>() {
                    public List<String> process(final DataManager dataManager) {
                        return dataManager.getAllSubjects();
                    }
                }));

        adapter.add(android.R.layout.simple_list_item_1, getViewProcessor1(R.string.inactive_subjects, new DataProcessor<List<Subject>>() {
            public List<Subject> process(final DataManager dataManager) {
                return dataManager.getInactiveSubjects();
            }
        }, R.string.no_inactive_subjects, R.string.choose_subjects_to_remove, R.string.please_choose_at_least_one_subject, new ActionRunner<Subject>() {
            public void performAction(final DataManager dataManager, final List<Subject> objects, final boolean[] checked) {
                dataManager.removeSubjects(objects, checked);
            }
        }, R.string.selected_subjects_were_successfully_removed));

        settingsList.setAdapter(adapter);
    }

    private ViewProcessor getViewProcessor2(final int menuItemTextResId,
                                            final String propertyName,
                                            final int dialogTitleResId,
                                            final int successMessageResId,
                                            final DataProcessor<List<String>> dataProcessor) {
        return new ViewProcessor() {
            private final SharedPreferences mySharedPreferences = getApplicationPreferences();
            private final String myNoValueString = getString(R.string.none);

            public Void process(final View view) {
                ((TextView) view.findViewById(android.R.id.text1)).setText(menuItemTextResId);
                updateDefaultValueTextView(view);
                view.setOnClickListener(new OnClickListener() {
                    public void onClick(final View v) {
                        DataUtil.perfromDataAction(Settings.this, R.string.loading, dataProcessor, new DataActionResultProcessor<List<String>>() {
                            public Void process(final List<String> list) {
                                final Dialog dialog = doCreateDialog(R.layout.simple_object_dialog, dialogTitleResId, new DialogProcessor() {
                                    public Void process(final Dialog dialog) {
                                        final String newDefaultValue = getTrimmedEditorText(dialog, R.id.object_editor);
                                        final Editor preferencesEditor = mySharedPreferences.edit();
                                        if (newDefaultValue.length() == 0) {
                                            preferencesEditor.remove(propertyName);
                                        } else {
                                            preferencesEditor.putString(propertyName, newDefaultValue);
                                        }
                                        preferencesEditor.commit();
                                        showShortToast(successMessageResId);
                                        dialog.dismiss();
                                        updateDefaultValueTextView(view);
                                        return null;
                                    }
                                });
                                dialog.setOwnerActivity(Settings.this);
                                final ImprovedAutoCompleteTextEdit objectEditor = (ImprovedAutoCompleteTextEdit) dialog.findViewById(R.id.object_editor);
                                setAutoCompleteAdapter(objectEditor, list);
                                objectEditor.asTextView().setText(mySharedPreferences.getString(propertyName, ""));
                                dialog.show();
                                return null;
                            }
                        });
                    }
                });
                return null;
            }

            private void updateDefaultValueTextView(final View view) {
                final TextView defaultValueTextView = (TextView) view.findViewById(android.R.id.text2);
                defaultValueTextView.setText(mySharedPreferences.getString(propertyName, myNoValueString));
            }
        };
    }

    private <T extends SimpleObject> ViewProcessor getViewProcessor1(final int textResId,
                                                                     final DataProcessor<List<T>> dataProcessor,
                                                                     final int noInactiveItemsMessageResId,
                                                                     final int titleResId,
                                                                     final int pleaseChooseMessageResId,
                                                                     final ActionRunner<T> actionRunner,
                                                                     final int successMessageResId) {
        return new ViewProcessor() {
            public Void process(final View view) {
                ((TextView) view).setText(textResId);
                view.setOnClickListener(new OnClickListener() {
                    public void onClick(final View view) {
                        DataUtil.perfromDataAction(Settings.this, R.string.loading, dataProcessor, new DataActionResultProcessor<List<T>>() {
                            public Void process(final List<T> inactiveItems) {
                                final int size = inactiveItems.size();
                                if (size == 0) {
                                    showShortToast(noInactiveItemsMessageResId);
                                    return null;
                                }
                                final boolean[] checked = new boolean[size];
                                for (int i = 0; i < size; i++) {
                                    checked[i] = false;
                                }
                                final AlertDialog.Builder builder = new AlertDialog.Builder(Settings.this);
                                builder.setTitle(titleResId);
                                builder.setMultiChoiceItems(makeStringArray(inactiveItems), null, new OnMultiChoiceClickListener() {
                                    public void onClick(final DialogInterface dialog, final int which, final boolean isChecked) {
                                        checked[which] = isChecked;
                                    }
                                });
                                builder.setPositiveButton(R.string.remove, new DialogInterface.OnClickListener() {
                                    public void onClick(final DialogInterface dialog, final int which) {
                                        if (!hasCheckedItem(checked)) {
                                            showShortToast(pleaseChooseMessageResId);
                                            return;
                                        }
                                        DataUtil.perfromDataAction(Settings.this, R.string.removing, new DataProcessor<Void>() {
                                            public Void process(final DataManager dataManager) {
                                                actionRunner.performAction(dataManager, inactiveItems, checked);
                                                return null;
                                            }
                                        }, new DataActionResultProcessor<Void>() {
                                            public Void process(final Void v) {
                                                showShortToast(successMessageResId);
                                                dialog.dismiss();
                                                return null;
                                            }
                                        });
                                    }

                                    private boolean hasCheckedItem(final boolean[] checkedItems) {
                                        for (final boolean checkedItem : checkedItems) {
                                            if (checkedItem) return true;
                                        }
                                        return false;
                                    }
                                });
                                builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                                    public void onClick(final DialogInterface dialog, final int which) {
                                        dialog.cancel();
                                    }
                                });
                                builder.create().show();
                                return null;
                            }
                        });
                    }
                });
                return null;
            }
        };
    }

    private static interface ActionRunner<T extends SimpleObject> {
        public void performAction(final DataManager dataManager, final List<T> objects, final boolean[] checked);
    }

    private String[] makeStringArray(final List<? extends SimpleObject> objects) {
        final String[] array = new String[objects.size()];
        int i = 0;
        for (final SimpleObject object : objects) {
            array[i++] = object.getName();
        }
        return array;
    }

    private static class SettingsListAdapter extends BaseAdapter {
        private final List<Pair<Integer, ViewProcessor>> myPairs;
        private final Map<Integer, Integer> myViewTypes;
        private final LayoutInflater myInflater;

        public SettingsListAdapter(final Context context) {
            super();
            myPairs = new ArrayList<Pair<Integer, ViewProcessor>>();
            myViewTypes = new HashMap<Integer, Integer>();
            myInflater = LayoutInflater.from(context);
        }

        public void add(final int layoutId, final ViewProcessor viewProcessor) {
            myPairs.add(Pair.create(layoutId, viewProcessor));
            if (!myViewTypes.containsKey(layoutId)) {
                myViewTypes.put(layoutId, myViewTypes.size());
            }
        }

        @Override
        public int getItemViewType(final int position) {
            return myViewTypes.get(myPairs.get(position).getFirst());
        }

        @Override
        public int getViewTypeCount() {
            return myViewTypes.size();
        }

        public int getCount() {
            return myPairs.size();
        }

        public Object getItem(final int position) {
            return null;
        }

        public long getItemId(final int position) {
            return 0;
        }

        public View getView(final int position, final View convertView, final ViewGroup parent) {
            final Pair<Integer, ViewProcessor> pair = myPairs.get(position);
            final int layoutId = pair.getFirst();
            final ViewProcessor viewProcessor = pair.getSecond();

            View view;

            if (convertView == null) {
                view = myInflater.inflate(layoutId, parent, false);
            } else {
                view = convertView;
            }

            viewProcessor.process(view);

            return view;
        }
    }

    private static interface ViewProcessor extends GenericProcessor<Void, View> {
    }
}
